'use strict';

const { Service } = require('ee-core');

const ModbusRTU = require("modbus-serial");
const crc16 = require('crc').crc16;
const Electron = require('ee-core/electron');
const { sendMsg, uint8ArrayToHex } = require('../common');
/**
 * 示例服务（service层为单例）
 * @class
 */
class ModbusOverTCPService extends Service {

    constructor(ctx) {
        super(ctx);

        // 创建 TCP 客户端
        this.client = new ModbusRTU();
        this.client.setTimeout(1000);
        this.client._debugEnabled = true;
    }

    async connect(args) {
        const ip = args.ip; // PLC 的 IP 地址
        const port = args.port; // Modbus TCP 端口

        // 连接到 Modbus TCP 服务器
        let res = await this.client.connectTcpRTUBuffered(ip, { port });
        // let res = await this.client.connectTCP(ip, { port, });

        // 使用内部方法监听接收数据事件
        this.client._port.on('data', (data) => {

            console.log('Received data:', data);
            // 主动向前端发请求
            sendMsg(data.toString('hex'), 'receive');
        });

        // 启用调试模式：监听发送和接收的数据
        this.client.on("debug", (data) =>{
            // data 是一个对象，包含以下属性：
            // - action: 描述当前动作（如 "send tcp"、"receive tcp"、"send rtu" 等）
            // - data: 原始数据（Buffer）
            console.log(`Action: ${data.action}`);
            console.log(`Data (hex): ${data.data.toString('hex')}`);
            console.log("---");
        });

        return res;
    }

    // 检查连接状态
    async checkConnect() {
        return this.client.connecting;
    }

    async send(args) {
        if (this.client.connecting == false) {
            throw new Error({ message: '未连接！'});
        }
        // 从数组创建 Buffer
        // let bufArr = [0x01, 0x01, 0x00, 0x00, 0x00, 0x04];
        let bufStr = args.value;

        // 构建PDU：功能码0x01（读线圈），起始地址0x0000，线圈数量0x000A（10个）
        const pdu = Buffer.from(bufStr, 'hex');
        // 使用内部方法发送
        this.client._port.write(pdu);
    }

    // 构建请求帧的函数
    async buildModbusRequest(functionCode, startAddress, quantity) {

        // 创建请求帧的字节数组
        let request = new Uint8Array(7); // Modbus RTU帧通常是7个字节（地址+功能码+数据+CRC16）
        request[0] = 0x01; // 设备地址（例如，0x01）
        request[1] = functionCode; // 功能码（例如，0x03表示读取保持寄存器）
        request[2] = (startAddress >> 8) & 0xFF; // 起始地址的高字节
        request[3] = startAddress & 0xFF; // 起始地址的低字节
        request[4] = (quantity >> 8) & 0xFF; // 要读取的数量（可选，取决于功能码）
        request[5] = quantity & 0xFF; // 要读取的数量（可选，取决于功能码）
        console.log('request', request);
        // 计算CRC16并添加到帧的末尾
        const crc = crc16(request); // 注意：在某些实现中，你可能需要传入不带CRC的数据部分进行计算
        console.log('crc:', crc);
        request[5] = crc & 0xFF; // CRC的低字节
        request[6] = (crc >> 8) & 0xFF; // CRC的高字节
        return request;
    }

    async close() { 
        // close the connection to the serialport
        // 关闭连接
        this.client.close();
    }

    async debug() {
        let request = ''
        if (this.client._transactions['1']) {
            request = this.client._transactions['1'].request;

            sendMsg(request.toString('hex'), 'send');
        }
    }

    // 读线圈数据(01H)
    async readCoils (args) { 
        // 设置从站地址（Slave ID）
        this.client.setID(args.id || 1); // 替换为你的设备地址（通常 1-247）
        // 示例：读取线圈寄存器（功能码 0x01）
        let startAddress = args.start || 0;
        let len = args.len || 2;
        let result = await this.client.readCoils(startAddress, len);
        this.debug();
        return result;
    }

    // 读离散输入寄存器(02H)
    async readDiscreteInputs (args) {
        this.client.setID(args.id || 1);
        let startAddress = args.start || 0;
        let len = args.len || 2;
        let result = await this.client.readDiscreteInputs(startAddress, len);
        this.debug();
        return result;
    } 

    // 读取保持数据(03H)
    async readHolding (args) { 
        // 设置从站地址（Slave ID）
        this.client.setID(args.id || 1); // 替换为你的设备地址（通常 1-247）
        // 示例：读取保持寄存器（功能码 0x03）
        let startAddress = args.start || 0;
        let len = args.len || 2;
        let result = this.client.readHoldingRegisters(startAddress, len);
        this.debug();
        return result;
    }

    // 读取输入寄存器(04H)
    async readInput (args) { 
        // 设置从站地址（Slave ID）
        this.client.setID(args.id || 1); // 替换为你的设备地址（通常 1-247）
        let startAddress = args.start;
        let len = args.len;
        let result = await this.client.readInputRegisters(startAddress, len);
        this.debug();
        return result;
    }

    // 写单个线圈寄存器(05H)
    async writeFC5 (args) { 
        // 设置从站地址（Slave ID）
        this.client.setID(args.id || 1); // 替换为你的设备地址（通常 1-247）
        let startAddress = args.start;
        let state = args.state;
        let result = await this.client.writeCoil(startAddress, state);
        this.debug();
        return result;
    }

    // 写单个保持寄存器(06H)
    async writeFC6 (args) { 
        // 设置从站地址（Slave ID）
        this.client.setID(args.id || 1); // 替换为你的设备地址（通常 1-247）
        let startAddress = args.start;
        let len = args.len;
        let result = await this.client.writeRegister(startAddress, len);
        this.debug();
        return result;    
    }

    // 轮询读取数据
    async polling(args) { 

    }

}

ModbusOverTCPService.toString = () => '[class ModbusOverTCPService]';
module.exports = ModbusOverTCPService;